package cz.apnetis.fitweb.server.entity;

import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.Index;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.jdo.annotations.Queries;
import javax.jdo.annotations.Query;
import javax.jdo.annotations.Version;
import javax.jdo.annotations.VersionStrategy;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

import cz.apnetis.fitweb.shared.DayFoodKind;
import cz.apnetis.fitweb.shared.Food;
import cz.apnetis.fitweb.shared.dto.FoodDTO;

@Queries ({
  @Query(name = "s.userId", language = "JDOQL",
      value = "select from cz.apnetis.fitweb.server.entity.FoodEntity where userId == :userId order by time desc"
  ),
  @Query(name = "s.period", language = "JDOQL",
      value = "select from cz.apnetis.fitweb.server.entity.FoodEntity where userId == :userId && time >= :timeFrom && time <= :timeTo order by time desc"
  )
})
@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
@Version(strategy = VersionStrategy.VERSION_NUMBER, column="version_number")
public class FoodEntity implements Food {

  @PrimaryKey
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  private Key key; public Key getKey() { return this.key; } public void setKey(final Key newKey) { this.key = newKey; }
  @Persistent
  @Index
  private String userId; @Override public String getUserId() { return this.userId; } public void setUserId(final String newUserId) { this.userId = newUserId; }
  @Persistent
  private String name; @Override public String getName() { return this.name; } @Override public void setName(final String newName) { this.name = newName; }
  @Persistent
  private String ingredientOverview; @Override public String getIngredientOverview() { return this.ingredientOverview; } @Override public void setIngredientOverview(final String newIngredientOverview) { this.ingredientOverview = newIngredientOverview; }
  @Persistent
  private Integer kj; @Override public Integer getKj() { return this.kj; } @Override public void setKj(final Integer newKj) { this.kj = newKj; }
  @Persistent
  private Date time; @Override public Date getTime() { return this.time; } @Override public void setTime(final Date newTime) { this.time = newTime; }
  @Persistent
  private DayFoodKind dayFoodKind; public DayFoodKind getDayFoodKind() { return this.dayFoodKind; } public void setDayFoodKind(final DayFoodKind newDayFoodKind) { this.dayFoodKind = newDayFoodKind; }
  /** Grams of proteins in food */
  @Persistent
  private Integer protein; public Integer getProtein() { return this.protein; } public void setProtein(final Integer protein) { this.protein = protein; }
  /** Grams of fat in food */
  @Persistent
  private Integer fat; public Integer getFat() { return this.fat; } public void setFat(final Integer fat) { this.fat = fat; }
  /** Grams of carbohydrate in food */
  @Persistent
  private Integer carbohydrate; public Integer getCarbohydrate() { return this.carbohydrate; } public void setCarbohydrate(final Integer carbohydrate) { this.carbohydrate = carbohydrate; }
  @Persistent
  private Integer glycemicIndex; public Integer getGlycemicIndex() { return this.glycemicIndex; } public void setGlycemicIndex(final Integer glycemicIndex) { this.glycemicIndex = glycemicIndex; }

  @Override public String getId() {
    if (this.key == null) { return null; }
    return KeyFactory.keyToString(getKey());
  }

  @Override public String getFoodKind() { return getDayFoodKind().toString(); }
  @Override public void setFoodKind(final String newFoodKind) { this.dayFoodKind = DayFoodKind.valueOf(newFoodKind); }

  /** Method which convert entity to dato */
  public final FoodDTO toDto() {
    final FoodDTO result = new FoodDTO();
    result.setId(getId());
    result.setUserId(getUserId());
    result.setName(getName());
    result.setKj(getKj());
    result.setTime(getTime());
    result.setFoodKind(getFoodKind());
    return result;
  }

  /** Method which transform data from DTO to this Food Entity */
  public final void fromDto(final Food food) {
    if (food == null) { throw new IllegalArgumentException("dto parameter mustn't be null"); }
    if (food.getId() != null && !"".equals(food.getId())) {
      setKey(KeyFactory.stringToKey(food.getId()));
    }
    setName(food.getName());
    setKj(food.getKj());
    setTime(food.getTime());
    setFoodKind(food.getFoodKind());
  }

  /** Abstract factory method which create Food Entity from given dto */
  public final static FoodEntity instanceFromDTO(final Food food) {
    final FoodEntity result = new FoodEntity();
    result.fromDto(food);
    return result;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
    + ((this.key == null) ? 0 : this.key.hashCode());
    return result;
  }

  @Override
  public boolean equals(final Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    final FoodEntity other = (FoodEntity) obj;
    if (this.key == null) {
      if (other.key != null) {
        return false;
      }
    } else if (!this.key.equals(other.key)) {
      return false;
    }
    return true;
  }

  @Override
  public String toString() {
    return getKey() + "|" + getName() + "|" + String.valueOf(getKj());
  }
}
